﻿using System.Collections.Generic;
using IQIGame.Onigao.Framework;
using NetProtocol.POD;

namespace IQIGame.Onigao.GamePlay
{
    /// <summary>
    /// 编队英雄数据
    /// </summary>
    public class FormationHeroData : IReusableClass
    {
        /// <summary>
        ///  英雄完整数据(缓存)
        /// </summary>
        public HeroData heroData { get; private set; }

        /// <summary>
        /// 归属者
        /// </summary>
        public FormationData belong { get; private set; }

        /// <summary>
        /// 编队中的位置
        /// </summary>
        public int pos { get; private set; }

        #region 配置 && 逻辑

        /// <summary>
        ///  英雄cid(缓存)
        /// </summary>
        public int cid => heroData?.cid ?? 0;

        public bool isHasHero => this.cid > 0;

        /// <summary>
        /// 是否是首发队员的位置
        /// </summary>
        public bool isRegularHeroPos => this.pos < APIUIFormation.FormBenchHeroStartPos;

        public bool isCaptain => this.cid > 0 && this.belong.captainHeroCid == this.cid;

        #endregion

        public FormationHeroData SetData(FormationData belong, int pos)
        {
            this.belong = belong;
            this.pos = pos;
            return this;
        }

        public FormationHeroData Sync(FormationHeroPOD heroPod)
        {
            HeroData data = GameDataCenter.PlayerData.hero.FindHeroDataById(heroPod.id);
            if (data == null)
            {
                this.ClearHero();
            }
            else
            {
                this.heroData = data;
            }

            return this;
        }

        public void Clear()
        {
            this.ClearHero();
            this.pos = 0;
            this.belong = null;
        }

        private void ClearHero()
        {
            this.heroData = null;
        }

        #region 对象池

        public uint MaxStore => 5;

        public void OnReset()
        {
            this.Clear();
        }

        public void Put2Pool()
        {
            ClassPool.Put(this);
        }

        static public FormationHeroData NewFromPool()
        {
            return ClassPool.Get<FormationHeroData>();
        }

        #endregion
    }

    /// <summary>
    /// 编队数据
    /// </summary>
    public class FormationData : IReusableClass
    {
        /// <summary>
        ///  编队序号
        /// </summary>
        public int formId { get; private set; } = -1;

        /// <summary>
        ///  编队名字，空表默认
        /// </summary>
        public string formName { get; private set; }

        /// <summary>
        ///  队长英雄cid
        /// </summary>
        public int captainHeroCid { get; private set; }

        /// <summary>
        ///  上阵英雄信息 -- 所有位置，pos->hero
        /// </summary>
        private Dictionary<int, FormationHeroData> m_heros;

        public Dictionary<int, FormationHeroData> heros
        {
            get
            {
                if (m_heros == null)
                {
                    m_heros = new();
                }

                return m_heros;
            }
            set
            {
                m_heros = value;
            }
        }

        /// <summary>
        /// 队伍战斗力
        /// </summary>
        public int fightPower { get; private set; } = 0;

        /// <summary>
        /// 上阵英雄数量
        /// </summary>
        public int heroCountInForm { get; private set; } = 0;

        public FormationData() { }

        public FormationData SetFormId(int formId)
        {
            this.formId = formId;
            return this;
        }

        public FormationData Sync(FormationPOD pod)
        {
            this.formId = pod.formId;
            this.formName = pod.formName;
            this.captainHeroCid = pod.captainHeroCid;
            this.heroCountInForm = 0;
            foreach (var item in pod.heroes)
            {
                if (this.heros.TryGetValue(item.Key, out var heroData))
                {
                    heroData.Sync(item.Value);
                }
                else
                {
                    heroData = FormationHeroData.NewFromPool().SetData(this, item.Key).Sync(item.Value);
                    this.heros[item.Key] = heroData;
                }

                if (heroData.isHasHero)
                    this.heroCountInForm++;
            }

            this.CalcFightPower();
            return this;
        }

        private void CalcFightPower()
        {
            int power = 0;
            HeroData heroData;
            foreach (var item in this.heros.Values)
            {
                heroData = item.heroData;
                if (heroData != null)
                {
                    power += heroData.fightPower;
                }
            }

            this.fightPower = power;
        }

        public FormationHeroData GetFormationHeroData(int pos)
        {
            return this.heros.TryGetValue(pos, out var posData) ? posData : null;
        }

        public FormationHeroData GetFormationHeroDataByHeroCid(int cid)
        {
            foreach (var item in this.heros.Values)
            {
                if (item.cid == cid)
                {
                    return item;
                }
            }

            return null;
        }

        public int GetFormationHeroPosByHeroCid(int cid)
        {
            foreach (var item in this.heros)
            {
                if (item.Value.cid == cid)
                {
                    return item.Key;
                }
            }

            return -1;
        }

        public void Clear()
        {
            this.formId = -1;
            this.formName = null;
            this.captainHeroCid = 0;
            if (this.m_heros != null)
            {
                foreach (var item in this.m_heros.Values)
                {
                    item.Put2Pool();
                }
            }

            this.m_heros = null;
            this.fightPower = 0;
            this.heroCountInForm = 0;
        }

        #region 对象池

        public uint MaxStore => 3;

        public void OnReset()
        {
            this.Clear();
        }

        public void Put2Pool()
        {
            ClassPool.Put(this);
        }

        static public FormationData NewFromPool()
        {
            return ClassPool.Get<FormationData>();
        }

        #endregion

        static public FormationData ConvertFromPOD(FormationPOD pod)
        {
            if (pod == null)
            {
                return null;
            }

            FormationData ret = NewFromPool().Sync(pod);
            return ret;
        }
    }

    public class FormationModuleData
    {
        private List<FormationData> listFormations;
        public int defFormId { get; private set; }

        public FormationData defaultFormationData
        {
            get
            {
                return this.GetFormation(defFormId);
            }
        }

        public FormationModuleData(int defFormId)
        {
            this.defFormId = defFormId;
            int max = APIUIFormation.FormMaxCount;
            this.listFormations = new(max);
            for (int i = 0; i < max; i++)
            {
                this.listFormations.Add(FormationData.NewFromPool().SetFormId(i + 1));
            }
        }

        public void Clear()
        {
            foreach (var item in listFormations)
            {
                item.Put2Pool();
            }

            this.listFormations.Clear();
        }

        public FormationData GetFormation(int formId)
        {
            return GetFormationByIndex(formId - 1);
        }

        public FormationData GetFormationByIndex(int index)
        {
            return index >= 0 && index < listFormations.Count ? listFormations[index] : null;
        }

        public void UpdateDefaultFomrId(int defFormId)
        {
            this.defFormId = defFormId;
        }
    }
}
